﻿using System.Collections.Generic;
using System.Linq;
using MarriageFertility.Helpers;
using TaleWorlds.CampaignSystem;
using TaleWorlds.CampaignSystem.Actions;
using TaleWorlds.CampaignSystem.CampaignBehaviors;
using TaleWorlds.CampaignSystem.CharacterDevelopment;
using TaleWorlds.CampaignSystem.GameMenus;
using TaleWorlds.CampaignSystem.Party;
using TaleWorlds.CampaignSystem.Settlements;
using TaleWorlds.Core;
using TaleWorlds.Library;
using TaleWorlds.Localization;
using TaleWorlds.MountAndBlade.View;
using TaleWorlds.ScreenSystem;

namespace MarriageFertility.Behaviors
{
    public class ClinicBehavior : CampaignBehaviorBase
    {
        public override void RegisterEvents()
        {
            CampaignEvents.OnSessionLaunchedEvent.AddNonSerializedListener(this, OnSessionLaunched);
        }

        public override void SyncData(IDataStore dataStore) { }

        private void OnSessionLaunched(CampaignGameStarter campaignGameStarter)
        {
            GameMenuHelper gameMenuHelper = new GameMenuHelper(campaignGameStarter);

            gameMenuHelper.AddBasicOption("town", "visit_special_clinic", 
                "{=MF_VisitClinic}Visit the mysterious clinic", GameMenuOption.LeaveType.Continue, delegate
                {
                    GameMenu.SwitchToMenu("ad_menu_mf_clinic");
                }, 0);

            gameMenuHelper.Add("ad_menu_mf_clinic", 
                "{=MF_ClinicDescription}This is a mysterious clinic hidden deep within the town, adorned with ancient scrolls and mystical herb patterns on the walls. A seasoned old physician resides here, rumored to be skilled in both medicine and forbidden arts, capable of performing operations beyond imagination.{newline}{newline}" +
                                "The clinic offers the following special services:{newline}{newline}" +
                                "· Gender reassignment surgery: 5000{GOLD_ICON}{newline}" +
                                "· Abortion surgery: 2000{GOLD_ICON}{newline}" +
                                "· Face reshaping: 50000{GOLD_ICON}{newline}" +
                                "· Hero revival: 100000{GOLD_ICON}{newline}" +
                                "· Negative trait removal: 2000{GOLD_ICON}{newline}");

            gameMenuHelper.AddConditionOption(
                "ad_menu_mf_clinic", 
                "make_sex", 
                "{=MF_ChangeSex}Perform gender reassignment surgery", 
                GameMenuOption.LeaveType.Conversation, 
                ChangeSexCondition, 
                ChangeSexConsequence);

            gameMenuHelper.AddConditionOption(
                "ad_menu_mf_clinic", 
                "perform_abortion", 
                "{=MF_PerformAbortion}Perform abortion surgery", 
                GameMenuOption.LeaveType.Conversation, 
                AbortionCondition, 
                AbortionConsequence);

            gameMenuHelper.AddConditionOption(
                "ad_menu_mf_clinic",
                "reshape_face",
                "{=MF_ReshapeFace}Reshape face",
                GameMenuOption.LeaveType.Conversation,
                ReshapeFaceCondition,
                ReshapeFaceConsequence);

            gameMenuHelper.AddConditionOption(
                "ad_menu_mf_clinic",
                "revive_hero",
                "{=MF_ReviveHero}Revive hero",
                GameMenuOption.LeaveType.Conversation,
                ReviveHeroCondition,
                ReviveHeroConsequence);

            gameMenuHelper.AddConditionOption(
                "ad_menu_mf_clinic",
                "clear_negative_traits",
                "{=MF_ClearNegativeTraits}Remove negative traits",
                GameMenuOption.LeaveType.Conversation,
                ClearNegativeTraitsCondition,
                ClearNegativeTraitsConsequence);

            gameMenuHelper.AddResumeOption("ad_menu_mf_clinic", "town");
        }

        private bool ChangeSexCondition(MenuCallbackArgs args)
        {
            bool hasEnoughGold = Hero.MainHero.Gold >= 5000;
            if (!hasEnoughGold)
            {
                args.Tooltip = new TextObject("{=MF_NotEnoughGoldForSexChange}You don’t have enough gold (5000{GOLD_ICON}) for gender reassignment surgery!");
                args.IsEnabled = false;
                return false;
            }
            return true;
        }

        private void ChangeSexConsequence(MenuCallbackArgs args)
        {
            var heroList = GetInquiryHeroes();
            if (heroList.Count == 0)
            {
                InformationManager.DisplayMessage(new InformationMessage(new TextObject("{=MF_NoHeroesAvailable}No heroes available in the party!").ToString()));
                return;
            }

            MBInformationManager.ShowMultiSelectionInquiry(new MultiSelectionInquiryData(
                new TextObject("{=MF_SelectSurgeryTarget}Select surgery target").ToString(), 
                new TextObject("{=MF_ChooseHeroForSexChange}Please select the hero for gender reassignment surgery:").ToString(), 
                heroList, 
                true, 
                1, 
                1, 
                new TextObject("{=MF_ChangeSexConfirm}Change sex").ToString(), 
                new TextObject("{=MF_Cancel}Cancel").ToString(), 
                selectedHeroes =>
                {
                    Hero selectedHero = selectedHeroes.FirstOrDefault()?.Identifier as Hero;
                    if (selectedHero != null)
                    {
                        if (selectedHero == Hero.MainHero)
                        {
                            selectedHero.UpdatePlayerGender(!selectedHero.IsFemale);
                            GiveGoldAction.ApplyForCharacterToSettlement(Hero.MainHero, Settlement.CurrentSettlement, 5000);
                            InformationManager.DisplayMessage(new InformationMessage(new TextObject("{=MF_SexChangeSuccessMainHero}Gender reassignment surgery successful! {selectedHero}'s gender has been changed.").SetTextVariable("selectedHero",selectedHero.Name).ToString()));
                        }
                        else
                        {
                            selectedHero.UpdatePlayerGender(!selectedHero.IsFemale);
                            ChangeRelationAction.ApplyRelationChangeBetweenHeroes(Hero.MainHero, selectedHero, -50);
                            GiveGoldAction.ApplyForCharacterToSettlement(Hero.MainHero, Settlement.CurrentSettlement, 5000);
                            InformationManager.DisplayMessage(new InformationMessage(new TextObject("{=MF_SexChangeSuccess}Gender reassignment surgery successful! {selectedHero}'s gender has been changed.").SetTextVariable("selectedHero",selectedHero.Name).ToString()));
                        }
                    }
                    else
                    {
                        InformationManager.DisplayMessage(new InformationMessage(new TextObject("{=MF_HeroNotFound}Specified hero not found!").ToString()));
                    }
                    GameMenu.SwitchToMenu("ad_menu_mf_clinic");
                }, null
            ));
        }

        private static List<InquiryElement> GetInquiryHeroes()
        {
            var inquiry = new List<InquiryElement>();
            var memberRoster = MobileParty.MainParty?.MemberRoster;
            var prisonRoster = MobileParty.MainParty?.PrisonRoster;

            if (memberRoster != null && memberRoster.Count > 0)
            {
                for (int i = 0; i < memberRoster.Count; i++)
                {
                    CharacterObject characterObject = memberRoster.GetCharacterAtIndex(i);
                    if (characterObject.IsHero)
                    {
                        inquiry.Add(new InquiryElement(characterObject.HeroObject, characterObject.Name.ToString(), new ImageIdentifier(CharacterCode.CreateFrom(characterObject))));
                    }
                }
            }

            if (prisonRoster != null && prisonRoster.Count > 0)
            {
                for (int i = 0; i < prisonRoster.Count; i++)
                {
                    CharacterObject characterObject = prisonRoster.GetCharacterAtIndex(i);
                    if (characterObject.IsHero)
                    {
                        inquiry.Add(new InquiryElement(characterObject.HeroObject, characterObject.Name.ToString(), new ImageIdentifier(CharacterCode.CreateFrom(characterObject))));
                    }
                }
            }
            return inquiry;
        }

        private static List<InquiryElement> GetBadInquiryHeroes()
        {
            var inquiry = new List<InquiryElement>();
            var memberRoster = MobileParty.MainParty?.MemberRoster;
            var prisonRoster = MobileParty.MainParty?.PrisonRoster;

            if (memberRoster != null && memberRoster.Count > 0)
            {
                for (int i = 0; i < memberRoster.Count; i++)
                {
                    CharacterObject characterObject = memberRoster.GetCharacterAtIndex(i);
                    if (characterObject.IsHero && characterObject.HeroObject.HasBadTraits())
                    {
                        inquiry.Add(new InquiryElement(characterObject.HeroObject, characterObject.Name.ToString(), new ImageIdentifier(CharacterCode.CreateFrom(characterObject))));
                    }
                }
            }

            if (prisonRoster != null && prisonRoster.Count > 0)
            {
                for (int i = 0; i < prisonRoster.Count; i++)
                {
                    CharacterObject characterObject = prisonRoster.GetCharacterAtIndex(i);
                    if (characterObject.IsHero && characterObject.HeroObject.HasBadTraits())
                    {
                        inquiry.Add(new InquiryElement(characterObject.HeroObject, characterObject.Name.ToString(), new ImageIdentifier(CharacterCode.CreateFrom(characterObject))));
                    }
                }
            }
            return inquiry;
        }

        private bool AbortionCondition(MenuCallbackArgs args)
        {
            var pregnantHeroes = GetPregnantHeroes();
            if (pregnantHeroes.Count == 0)
            {
                args.Tooltip = new TextObject("{=MF_NoPregnantHeroes}No pregnant heroes in the party, abortion surgery unavailable!");
                args.IsEnabled = false;
                return true;
            }

            bool hasEnoughGold = Hero.MainHero.Gold >= 2000;
            if (!hasEnoughGold)
            {
                args.Tooltip = new TextObject("{=MF_NotEnoughGoldForAbortion}You don’t have enough gold (2000{GOLD_ICON}) for abortion surgery!");
                args.IsEnabled = false;
                return true;
            }
            return true;
        }

        private void AbortionConsequence(MenuCallbackArgs args)
        {
            var heroList = GetPregnantHeroes();
            if (heroList.Count == 0)
            {
                InformationManager.DisplayMessage(new InformationMessage(new TextObject("{=MF_NoPregnantHeroes}No pregnant heroes in the party!").ToString()));
                return;
            }

            MBInformationManager.ShowMultiSelectionInquiry(new MultiSelectionInquiryData(
                new TextObject("{=MF_SelectSurgeryTarget}Select surgery target").ToString(), 
                new TextObject("{=MF_ChooseHeroForAbortion}Please select the hero for abortion surgery:").ToString(), 
                heroList, 
                true, 
                1, 
                1, 
                new TextObject("{=MF_PerformAbortionConfirm}Perform abortion").ToString(), 
                new TextObject("{=MF_Cancel}Cancel").ToString(), 
                selectedHeroes =>
                {
                    Hero selectedHero = selectedHeroes.FirstOrDefault()?.Identifier as Hero;
                    if (selectedHero != null)
                    {
                        if (selectedHero.IsPlayerSpouse())
                        {
                            ChangeRelationAction.ApplyRelationChangeBetweenHeroes(Hero.MainHero, selectedHero, -20);
                            InformationManager.DisplayMessage(new InformationMessage(new TextObject("{=MF_AbortionSuccessSpouse}{selectedHero}’s abortion surgery was successful!").SetTextVariable("selectedHero",selectedHero.Name).ToString()));
                        }
                        else
                        {
                            ChangeRelationAction.ApplyRelationChangeBetweenHeroes(Hero.MainHero, selectedHero, -50);
                            InformationManager.DisplayMessage(new InformationMessage(new TextObject("{=MF_AbortionSuccess}{selectedHero}’s abortion surgery was successful!").SetTextVariable("selectedHero",selectedHero.Name).ToString()));
                        }
                        var pregnancyAction = Campaign.Current.GetCampaignBehavior<CustomerPregnancyCampaignBehavior>();
                        pregnancyAction.RemoveHeroPregnancy(selectedHero);
                        GiveGoldAction.ApplyForCharacterToSettlement(Hero.MainHero, Settlement.CurrentSettlement, 2000);
                    }
                    else
                    {
                        InformationManager.DisplayMessage(new InformationMessage(new TextObject("{=MF_HeroNotFound}Specified hero not found!").ToString()));
                    }
                    GameMenu.SwitchToMenu("ad_menu_mf_clinic");
                }, null
            ));
        }

        private static List<InquiryElement> GetPregnantHeroes()
        {
            var inquiry = new List<InquiryElement>();
            var memberRoster = MobileParty.MainParty?.MemberRoster;
            if (memberRoster != null && memberRoster.Count > 0)
            {
                for (int i = 0; i < memberRoster.Count; i++)
                {   
                    CharacterObject characterObject = memberRoster.GetCharacterAtIndex(i);
                    Hero hero = characterObject.HeroObject;
                    if (hero != null && hero.IsPregnant)
                    {
                        inquiry.Add(new InquiryElement(hero, hero.Name.ToString(), new ImageIdentifier(CharacterCode.CreateFrom(characterObject))));
                    }
                }
            }
            return inquiry;
        }

        private bool ReshapeFaceCondition(MenuCallbackArgs args)
        {
            bool hasEnoughGold = Hero.MainHero.Gold >= 50000;
            if (!hasEnoughGold)
            {
                args.Tooltip = new TextObject("{=MF_NotEnoughGoldForFaceReshape}You don’t have enough gold (50000{GOLD_ICON}) for face reshaping!");
                args.IsEnabled = false;
                return true;
            }

            var heroList = GetInquiryHeroes();
            if (heroList.Count == 0)
            {
                args.Tooltip = new TextObject("{=MF_NoHeroesAvailable}No heroes available in the party!");
                args.IsEnabled = false;
                return true;
            }
            return true;
        }

        private static List<InquiryElement> GetDeadHeroes()
        {
            var inquiry = new List<InquiryElement>();
            foreach (Hero hero in Hero.DeadOrDisabledHeroes)
            {
                if (!hero.IsDisabled)
                    inquiry.Add(new InquiryElement(hero, hero.Name.ToString(), new ImageIdentifier(CharacterCode.CreateFrom(hero.CharacterObject))));
            }
            return inquiry;
        }

        private void ReshapeFaceConsequence(MenuCallbackArgs args)
        {
            var heroList = GetInquiryHeroes();
            if (heroList.Count == 0)
            {
                InformationManager.DisplayMessage(new InformationMessage(new TextObject("{=MF_NoHeroesAvailable}No heroes available in the party!").ToString()));
                return;
            }

            MBInformationManager.ShowMultiSelectionInquiry(new MultiSelectionInquiryData(
                new TextObject("{=MF_SelectFaceReshapeTarget}Select hero for face reshaping").ToString(), 
                new TextObject("{=MF_ChooseHeroForFaceReshape}Please select the hero for face reshaping:").ToString(), 
                heroList, 
                true, 
                1, 
                1, 
                new TextObject("{=MF_Confirm}Confirm").ToString(), 
                    new TextObject("{=MF_Cancel}Cancel").ToString(), 
                selectedHeroes =>
                {
                    Hero selectedHero = selectedHeroes.FirstOrDefault()?.Identifier as Hero;
                    if (selectedHero != null)
                    {
                        FaceGen.ShowDebugValues = true;
                        ScreenManager.PushScreen(ViewCreator.CreateMBFaceGeneratorScreen(selectedHero.CharacterObject, false, null));
                        GiveGoldAction.ApplyForCharacterToSettlement(Hero.MainHero, Settlement.CurrentSettlement, 50000);
                    }
                    else
                    {
                        InformationManager.DisplayMessage(new InformationMessage(new TextObject("{=MF_HeroNotFound}Specified hero not found!").ToString()));
                    }
                    GameMenu.SwitchToMenu("ad_menu_mf_clinic");
                }, null
            ));
        }

        private bool ReviveHeroCondition(MenuCallbackArgs args)
        {
            bool hasEnoughGold = Hero.MainHero.Gold >= 100000;
            if (!hasEnoughGold)
            {
                args.Tooltip = new TextObject("{=MF_NotEnoughGoldForRevival}You don’t have enough gold (100000{GOLD_ICON}) to revive a hero!");
                args.IsEnabled = false;
                return true;
            }

            var deadHeroes = GetDeadHeroes();
            if (deadHeroes.Count == 0)
            {
                args.Tooltip = new TextObject("{=MF_NoDeadHeroes}No heroes available to revive!");
                args.IsEnabled = false;
                return true;
            }
            return true;
        }

        private void ReviveHeroConsequence(MenuCallbackArgs args)
        {
            var heroList = GetDeadHeroes();
            if (heroList.Count == 0)
            {
                InformationManager.DisplayMessage(new InformationMessage(new TextObject("{=MF_NoDeadHeroes}No heroes available to revive!").ToString()));
                return;
            }

            MBInformationManager.ShowMultiSelectionInquiry(new MultiSelectionInquiryData(
                new TextObject("{=MF_SelectReviveTarget}Select hero to revive").ToString(), 
                new TextObject("{=MF_ChooseHeroForRevival}Please select the hero to revive:").ToString(), 
                heroList, 
                true, 
                1, 
                1, 
                new TextObject("{=MF_ReviveConfirm}Revive").ToString(), 
                new TextObject("{=MF_Cancel}Cancel").ToString(), 
                selectedHeroes =>
                {
                    Hero selectedHero = selectedHeroes.FirstOrDefault()?.Identifier as Hero;
                    if (selectedHero != null)
                    {
                        if (selectedHero.HeroDeveloper == null)
                        {
                            HeroDeveloper value2 = ReflectUtils.CreateInstance<HeroDeveloper>(new object[] { selectedHero });
                            ReflectUtils.ReflectFieldAndSetValue("_heroDeveloper", value2, selectedHero);
                            selectedHero.Init();
                        }
                        selectedHero.HitPoints = selectedHero.MaxHitPoints;
                        selectedHero.ChangeState(Hero.CharacterStates.Active);
                        selectedHero.DeathDay = CampaignTime.Never;
                        selectedHero.AddDeathMark();
                        Settlement settlement = selectedHero.HomeSettlement ?? Settlement.GetFirst;
                        TeleportHeroAction.ApplyImmediateTeleportToSettlement(selectedHero, settlement);
                        selectedHero.EncyclopediaText = new TextObject("{=MF_RevivalEncyclopediaUpdate}{selectedHero.EncyclopediaText};{selectedHero.Name} has been revived!");
                        if (selectedHero.Occupation == Occupation.Soldier)
                        {
                            selectedHero.SetNewOccupation(Occupation.Wanderer);
                        }
                        GiveGoldAction.ApplyForCharacterToSettlement(Hero.MainHero, Settlement.CurrentSettlement, 100000);
                        InformationManager.DisplayMessage(new InformationMessage(new TextObject("{=MF_RevivalSuccess}{selectedHero} has been successfully revived!").SetTextVariable("selectedHero",selectedHero.Name).ToString()));
                    }
                    else
                    {
                        InformationManager.DisplayMessage(new InformationMessage(new TextObject("{=MF_HeroNotFound}Specified hero not found!").ToString()));
                    }
                    GameMenu.SwitchToMenu("ad_menu_mf_clinic");
                }, null
            ));
        }

        private bool ClearNegativeTraitsCondition(MenuCallbackArgs args)
        {
            bool hasEnoughGold = Hero.MainHero.Gold >= 2000;
            if (!hasEnoughGold)
            {
                args.Tooltip = new TextObject("{=MF_NotEnoughGoldForTraitRemoval}You don’t have enough gold (2000{GOLD_ICON}) to remove negative traits!");
                args.IsEnabled = false;
                return false;
            }

            var heroList = GetInquiryHeroes();
            if (heroList.Count == 0)
            {
                args.Tooltip = new TextObject("{=MF_NoHeroesAvailable}No heroes available in the party!");
                args.IsEnabled = false;
                return false;
            }
            return true;
        }

        private void ClearNegativeTraitsConsequence(MenuCallbackArgs args)
        {
            var heroList = GetBadInquiryHeroes();
            if (heroList.Count == 0)
            {
                InformationManager.DisplayMessage(new InformationMessage(new TextObject("{=MF_NoHeroesAvailable}No heroes available in the party!").ToString()));
                return;
            }

            MBInformationManager.ShowMultiSelectionInquiry(new MultiSelectionInquiryData(
                new TextObject("{=MF_SelectTraitRemovalTarget}Select hero to remove negative traits").ToString(), 
                new TextObject("{=MF_ChooseHeroForTraitRemoval}Please select the hero to remove negative traits:").ToString(), 
                heroList, 
                true, 
                1, 
                1, 
                new TextObject("{=MF_ClearConfirm}Clear").ToString(), 
                new TextObject("{=MF_Cancel}Cancel").ToString(), 
                selectedHeroes =>
                {
                    Hero selectedHero = selectedHeroes.FirstOrDefault()?.Identifier as Hero;
                    if (selectedHero != null)
                    {
                        var negativeTraits = Helper.RelevantTraits;
                        foreach (var trait in negativeTraits)
                        {
                            if (selectedHero.GetTraitLevel(trait) < 0)
                            {
                                selectedHero.SetTraitLevel(trait, 0);
                            }
                        }
                        GiveGoldAction.ApplyForCharacterToSettlement(Hero.MainHero, Settlement.CurrentSettlement, 10000);
                        InformationManager.DisplayMessage(new InformationMessage(new TextObject("{=MF_TraitRemovalSuccess}{selectedHero}’s negative traits have been successfully removed!").SetTextVariable("selectedHero",selectedHero.Name).ToString()));
                    }
                    else
                    {
                        InformationManager.DisplayMessage(new InformationMessage(new TextObject("{=MF_HeroNotFound}Specified hero not found!").ToString()));
                    }
                    GameMenu.SwitchToMenu("ad_menu_mf_clinic");
                }, null
            ));
        }
    }
}